package com.eian.boot.helper;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

/**
 * API测试辅助工具
 *
 * <p>封装常用的HTTP请求和断言操作
 *
 * @author test
 */
public class ApiTestHelper {

    private final MockMvc mockMvc;
    private final ObjectMapper objectMapper;
    private final String token;

    public ApiTestHelper(MockMvc mockMvc, ObjectMapper objectMapper, String token) {
        this.mockMvc = mockMvc;
        this.objectMapper = objectMapper;
        this.token = token;
    }

    /**
     * 断言成功响应（code=200）
     */
    public static void assertSuccess(ResultActions resultActions) throws Exception {
        resultActions
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(200));
    }

    /**
     * 断言失败响应（code!=200）
     */
    public static void assertFail(ResultActions resultActions) throws Exception {
        MvcResult result = resultActions
                .andExpect(status().isOk())
                .andReturn();

        String responseBody = result.getResponse().getContentAsString();
        ObjectMapper mapper = new ObjectMapper();
        JsonNode jsonNode = mapper.readTree(responseBody);
        int code = jsonNode.get("code").asInt();

        assertThat(code).isNotEqualTo(200);
    }

    /**
     * 断言失败响应并检查消息
     */
    public static void assertFailWithMessage(ResultActions resultActions, String expectedMessage) throws Exception {
        MvcResult result = resultActions
                .andExpect(status().isOk())
                .andReturn();

        String responseBody = result.getResponse().getContentAsString();
        ObjectMapper mapper = new ObjectMapper();
        JsonNode jsonNode = mapper.readTree(responseBody);

        int code = jsonNode.get("code").asInt();
        String message = jsonNode.get("msg").asText();

        assertThat(code).isNotEqualTo(200);
        assertThat(message).contains(expectedMessage);
    }

    /**
     * 断言401未授权
     */
    public static void assertUnauthorized(ResultActions resultActions) throws Exception {
        resultActions.andExpect(status().isUnauthorized());
    }

    /**
     * 断言403禁止访问
     */
    public static void assertForbidden(ResultActions resultActions) throws Exception {
        resultActions.andExpect(status().isForbidden());
    }

    /**
     * 发送POST请求（带Token）
     */
    public ResultActions post(String url, Object requestBody) throws Exception {
        return mockMvc.perform(MockMvcRequestBuilders.post(url)
                        .header("satoken", token)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(requestBody)))
                .andDo(print());
    }

    /**
     * 发送POST请求（不带请求体）
     */
    public ResultActions postWithoutBody(String url) throws Exception {
        return mockMvc.perform(MockMvcRequestBuilders.post(url)
                        .header("satoken", token)
                        .contentType(MediaType.APPLICATION_JSON))
                .andDo(print());
    }

    /**
     * 发送GET请求（带Token）
     */
    public ResultActions get(String url) throws Exception {
        return mockMvc.perform(MockMvcRequestBuilders.get(url)
                        .header("satoken", token)
                        .contentType(MediaType.APPLICATION_JSON))
                .andDo(print());
    }

    /**
     * 发送GET请求（带参数）
     */
    public ResultActions getWithParams(String url, Object... params) throws Exception {
        return mockMvc.perform(MockMvcRequestBuilders.get(url, params)
                        .header("satoken", token)
                        .contentType(MediaType.APPLICATION_JSON))
                .andDo(print());
    }

    /**
     * 发送PUT请求
     */
    public ResultActions put(String url, Object requestBody) throws Exception {
        return mockMvc.perform(MockMvcRequestBuilders.put(url)
                        .header("satoken", token)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(requestBody)))
                .andDo(print());
    }

    /**
     * 发送DELETE请求
     */
    public ResultActions delete(String url) throws Exception {
        return mockMvc.perform(MockMvcRequestBuilders.delete(url)
                        .header("satoken", token)
                        .contentType(MediaType.APPLICATION_JSON))
                .andDo(print());
    }

    /**
     * 断言成功响应并返回data
     */
    public JsonNode assertSuccessAndGetData(ResultActions resultActions) throws Exception {
        MvcResult result = resultActions
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(200))
                .andReturn();

        String responseBody = result.getResponse().getContentAsString();
        JsonNode jsonNode = objectMapper.readTree(responseBody);
        return jsonNode.get("data");
    }

    /**
     * 提取响应中的data字段
     */
    public JsonNode extractData(ResultActions resultActions) throws Exception {
        MvcResult result = resultActions.andReturn();
        String responseBody = result.getResponse().getContentAsString();
        JsonNode jsonNode = objectMapper.readTree(responseBody);
        return jsonNode.get("data");
    }

    /**
     * 提取响应体
     */
    public String extractResponseBody(ResultActions resultActions) throws Exception {
        return resultActions.andReturn().getResponse().getContentAsString();
    }
}

